﻿using DotNetCore.CAP;
using Seagull.Foundation;

namespace Seagull.Extensions.ServiceBus
{
    public class ServicePublisher : IServiceBus
    {
        private readonly ICapPublisher _publisher;
        private readonly IEnumerable<IServiceBusFilter> _filters;

        public ServicePublisher(ICapPublisher publisher, IEnumerable<IServiceBusFilter> filters)
        {
            this._publisher = publisher;
            this._filters = filters;
        }

        public async Task Delay<T>(string name, T contentObj, TimeSpan delay, IDictionary<string, string?>? headers = null)
        {
            if (headers is null)
                headers = new Dictionary<string, string?> { { "x-delay", delay.TotalMilliseconds.ToString() } };
            else
                headers.Add("x-delay", delay.TotalMilliseconds.ToString());

            ServiceBusInvocationContext context = new(name, contentObj, headers);
            var resultValue = await InvocationFilter(context);
            if (resultValue)
            {
                await _publisher.PublishAsync(context.Name, context.Content, context.Headers);
            }
        }

        public async Task Publish<T>(string name, T contentObj, IDictionary<string, string?>? headers = null)
        {
            ServiceBusInvocationContext context = new(name, contentObj, headers);
            var resultValue = await InvocationFilter(context);
            if (resultValue)
            {
                if (context.Headers is null)
                    await _publisher.PublishAsync(context.Name, context.Content);
                else
                    await _publisher.PublishAsync(context.Name, context.Content, context.Headers);
            }
        }

        public async Task Send<T>(string name, T contentObj, IDictionary<string, string?>? headers = null)
        {
            ServiceBusInvocationContext context = new(name, contentObj, headers);
            var resultValue = await InvocationFilter(context);
            if (resultValue)
            {
                if (headers is null)
                    await _publisher.PublishAsync(context.Name, context.Content);
                else
                    await _publisher.PublishAsync(context.Name, context.Content, context.Headers);
            }
        }

        private async ValueTask<bool> InvocationFilter(ServiceBusInvocationContext context)
        {
            if (_filters.Any())
            {
                foreach (var filter in _filters)
                {
                    bool next = await filter.InvokeMethodAsync(context);
                    if (!next)
                        return false;
                }
            }
            return true;
        }
    }
}
